﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using System.Drawing.Design;

namespace NETXPF.WPF.PropertyList
{
    /// <summary>
    /// Interaction logic for PropertyList.xaml
    /// </summary>
    public partial class PropertyList : ItemsControl
    {
        ObservableCollection<PropertyItem> items;
        internal object obj;

        public event Action<PropertyItem> ItemEditClick;

        public PropertyList()
        {
            InitializeComponent();
            this.DataContextChanged += new DependencyPropertyChangedEventHandler(PropertyList_DataContextChanged);
            this.ItemEditClick += new Action<PropertyItem>(PropertyList_ItemEditClick);
        }

        void PropertyList_ItemEditClick(PropertyItem obj)
        {
            if (obj.Value is ICollection)
            {
                System.ComponentModel.Design.CollectionEditor colEdit = new System.ComponentModel.Design.CollectionEditor(obj.Value.GetType());
                RuntimeServiceProvider serviceProvider = new RuntimeServiceProvider();
                colEdit.EditValue(serviceProvider, serviceProvider, obj.Value);
            }
        }

        void PropertyList_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            items = new ObservableCollection<PropertyItem>();
            PropertyInfo[] properties = DataContext.GetType().GetProperties();
            //Array.Sort(properties, new Comparison<PropertyInfo>((a, b) => a.Name.CompareTo(b.Name)));
            obj = DataContext;
            foreach(PropertyInfo pi in properties)
            {
                if (pi.CanRead)
                {
                    items.Add(new PropertyItem { info = pi, list = this });
                }
            }
            ItemsSource = items;
        }

        private void zEdit_Click(object sender, RoutedEventArgs e)
        {
            if (ItemEditClick != null)
            {
                ItemEditClick((PropertyItem)(((System.Windows.Controls.Button)sender).DataContext));
            }
        }
    }
    public class PropertyItemSelector : DataTemplateSelector
    {
        public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
        {
            FrameworkElement fe = (FrameworkElement)container;
            PropertyInfo info = (PropertyInfo)item.GetType().GetProperty("Info").GetValue(item, null);
            foreach (object attr in info.GetCustomAttributes(typeof(BrowsableAttribute), true))
            {
                if (!((BrowsableAttribute)attr).Browsable)
                {
                    return (DataTemplate)fe.FindResource("Default_Hidden");
                }
            }
            foreach (object attr in info.GetCustomAttributes(typeof(EditorTemplateAttribute), true))
            {
                return (DataTemplate)fe.FindResource(((EditorTemplateAttribute)attr).ResourceKey);
            }
            if(info.PropertyType.IsAssignableFrom(typeof(string)))
            {
                return (DataTemplate)fe.FindResource("Default_StringTemplate");
            }
            if(info.PropertyType.IsEnum)
            {
                return (DataTemplate)fe.FindResource("Default_EnumTemplate");
            }
            if (info.PropertyType.IsAssignableFrom(typeof(DateTime)))
            {
                return (DataTemplate)fe.FindResource("Default_DateTemplate");
            }
            if (info.PropertyType.IsAssignableFrom(typeof(decimal)) || info.PropertyType.IsAssignableFrom(typeof(double)) || info.PropertyType.IsAssignableFrom(typeof(int))
                || info.PropertyType.IsAssignableFrom(typeof(float)) || info.PropertyType.IsAssignableFrom(typeof(long)) || info.PropertyType.IsAssignableFrom(typeof(byte))
                || info.PropertyType.IsAssignableFrom(typeof(short)))
            {
                return (DataTemplate)fe.FindResource("Default_NumericTemplate");
            }
            //use an 'unknown type' template
            return (DataTemplate)fe.FindResource("Default_UnknownTemplate");
        }
    }
    public class PropertyItem : DependencyObject
    {
        internal PropertyInfo info;
        internal PropertyList list;
        public object Content
        {
            get
            {
                SetValue(ContentProperty, info.GetValue(list.obj, null));
                return GetValue(ContentProperty);
            }
            set
            {
                SetValue(ContentProperty, value);
                info.SetValue(list.obj, value, null);
            }
        }
        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof(object),
              typeof(PropertyItem), new UIPropertyMetadata(""));
        public PropertyInfo Info
        {
            get
            {
                return info;
            }
        }
        public PropertyList List
        {
            get
            {
                return list;
            }
        }
        public object Object
        {
            get
            {
                return list.obj;
            }
        }
        public string PropertyName
        {
            get
            {
                return info.Name;
            }
        }
        public string Type
        {
            get
            {
                return info.PropertyType.FullName;
            }
        }
        public object Value
        {
            get
            {
                return Content;
            }
            set
            {
                Content = value;
            }
        }
        public bool IsEnabled
        {
            get
            {
                foreach (object attr in info.GetCustomAttributes(typeof(ReadOnlyAttribute), true))
                {
                    if (((ReadOnlyAttribute)attr).IsReadOnly)
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        public Visibility ItemVisibility
        {
            get
            {
                foreach (object attr in info.GetCustomAttributes(typeof(BrowsableAttribute), true))
                {
                    if (!((BrowsableAttribute)attr).Browsable)
                    {
                        return Visibility.Collapsed;
                    }
                }
                return Visibility.Visible;
            }
        }
    }
    [AttributeUsage(AttributeTargets.Property)]
    public class EditorTemplateAttribute : Attribute
    {
        string resourceKey;
        public EditorTemplateAttribute(string resourceKey)
        {
            this.resourceKey = resourceKey;
        }
        public string ResourceKey
        {
            get
            {
                return resourceKey;
            }
        }
    }
    public class NumericConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return decimal.Parse((string)value);
        }
    }
    public class RuntimeServiceProvider : IServiceProvider, ITypeDescriptorContext
    {
        #region IServiceProvider Members

        object IServiceProvider.GetService(Type serviceType)
        {
            if (serviceType == typeof(IWindowsFormsEditorService))
            {
                return new WindowsFormsEditorService();
            }

            return null;
        }

        class WindowsFormsEditorService : IWindowsFormsEditorService
        {
            #region IWindowsFormsEditorService Members

            public void DropDownControl(System.Windows.Forms.Control control)
            {
            }

            public void CloseDropDown()
            {
            }

            public System.Windows.Forms.DialogResult ShowDialog(Form dialog)
            {
                return dialog.ShowDialog();
            }

            #endregion
        }

        #endregion

        #region ITypeDescriptorContext Members

        public void OnComponentChanged()
        {
        }

        public IContainer Container
        {
            get { return null; }
        }

        public bool OnComponentChanging()
        {
            return true; // true to keep changes, otherwise false
        }

        public object Instance
        {
            get { return null; }
        }

        public PropertyDescriptor PropertyDescriptor
        {
            get { return null; }
        }

        #endregion
    }
}
